10 Django 使用 uWSGI 和 Nginx 部署

千锋教育的 Django 教程[1] 中没有部署,网上翻了很久,终于搞清楚了大致情况,现记录以备使用。

运行环境:一台主机、一个虚拟机。主机模拟客户端,虚拟机模拟服务器。

主机:Win 10

虚拟机:Ubuntu 22.04 LTS


所有操作,通篇阅读后,按需执行。


一、知识储备

uWSGINginx 介绍及工作流程,略。

太晚了,找时间补上。

二、安装必备软件

默认 PythonVirtualenvpipDjango 需要的模块已经安装完成。

项目目录说明:

Pycharm 中的项目名称为 Retrieve ,其结构如 图 1 所示。

5.png|图 1 Retrieve 目录结构

Jesus,根本截不全。不过也够说明问题了。

记两个目录:一个是项目根目录,其路径为 /home/breky/Workspace/djangodemo/Retrieve;另一个是与项目目录同名的目录 Retrieve,其路径为 /home/breky/Workspace/djangodemo/Retrieve/Retrieve,其下有一个 wsgi.py 文件,这个文件配置 uWSGI 时要用。

1. 安装及配置 uWSGI

网上有很多介绍,安装 uWSGI 是使用 sudo apt 命令安装,我没成功;还有一些说要安装两次,第一次正常安装,第二次在虚拟环境下安装,也没说清楚是用什么命令安装的。直接看到一篇文章说用 pip 安装,才知道 uWSGI 可以用 pip 安装。那安装两次,想来也是系统环境下安装一次,虚拟环境下安装一次。但是想想是不是只需要在虚拟环境下安装就可以了。试试呗,生命在于折腾!!!!

Here We Go!

虚拟环境名称为 Django,进入虚拟环境,workon Django

然后再安装 uWSGIsudo pip install uwsgi

在项目的根目录下配置项目的 uwsgiini 文件。图 1 中倒数年第二个文件就是,其内容如下。

[uwsgi]
# 与 nginx 通信和接口
socket = 127.0.0.1:8080
# 项目根目录路径
chdir = /home/breky/Workspace/djangodemo/Retrieve
# 在项目根目录下,与项目同名目录下的 wsgi.py 文件,与 python 导包方式相同
module = Retrieve.wsgi:application
master = True
processes = 2
vacuum = True
max-requests = 5000
# 这个得是 uwsgi 的日志文件,图 1 中倒数第一个文件
# 在这个位置新建 .log 文件,然后把路径写对就好了
# 在哪写都行,只要路径写对、有读写权限就行。
daemonize = /home/breky/Workspace/djangodemo/Retrieve/Retrieve_uwsgi.log

# 修改 python 文件时,不用重启,自动刷新。为这个命令,遭了老罪了。
py-autoreload = 1

还在虚拟环境中,还在项目根目录下(/home/breky/Workspace/djangodemo/Retrieve),执行下面的命令

uwsgi --ini Retrieve_uwsgi.ini

可以了,用 127.0.0.1:8080 访问。不出意外的出了意外,失败了。提示的大致意思好像是访问的链接被重定向、还是重置了,没载到图,是因为还没有配置 Nginx

Nginx 接收外部的访问链接,然后传给 uWSGI,再由 uWSGI 传给 Django。现在只是配置好了 uWSGI,还需要配置 Nginx。记住上面 socket 的值(127.0.0.1:8080),这个接口要与 Nginx 通信[2]

2. 安装及配置 Nginx

这个用系统命令安装的, sudo apt install nginx。如果报错,先更新系统,再安装。

sudo apt update
sudo apt upgrade
sudo apt install nginx

配置 nginx,需要更改 /etc/nginx/sites-available/ 下的 default 文件,所以先备份,再修改。

cd /etc/nginx/sites-available
sudo cp default default.bak

修改内容,sudo vim default(没有 vim,安装一下。sudo apt install vim),把 server 部分的内容修改一下就好。

server {
	listen 80 default_server;
	listen [::]:80 default_server;
	root /var/www/html;
	index index.html index.htm index.nginx-debian.html;
	server_name 192.168.106.132;
	location / {
		include uwsgi_params;
		uwsgi_pass 127.0.0.1:8080;
		uwsgi_param UWSGI_CHDIR /home/breky/Workspace/djangodemo/Retrieve;
		uwsgi_param UWSGI_SCRIPT Retrieve.wsgi;
		client_max_body_size 35m;
	}
}

其他的都不用改,需要改以下几个地方:

  1. server_name:域名或者主机 IP 地址。192.168.106.132 是虚拟机 IP 地址,用这个地址访问项目;
  2. include uwsgi_params:这个需要手动添加。uwsgi_params 不要写错,最后结尾有 s
  3. uwsgi_pass:这个值与 Retrieve_uwsgi.ini 中的 socket 的值一致。nginxuWSGI 通信的接口;
  4. uwsgi_param UWSGI_CHDIR:这个也是手动添加。后面跟的路径是项目根目录的路径,与 Retrieve_uwsgi.ini 中的 chdir 是同一个值。uwsgi_param,没有 s 了;
  5. uwsgi_param UWSGI_SCRIPT:这个还是手动添加。指向与项目同名目录 Retrieve 中的 wsgi.py 文件。与 python 导包方式一样,不写扩展名,Retrieve.wsgi

启动 nginx 服务

sudo systemctl start nginx

可以用 server_name 的值(192.168.106.132)访问网站了,我这里也成功了。

三、开机启动

NginxuWSGI 默认是不会随机启动的,需要手动开启,不然服务器重启网站不能访问了。

设置 Nginx 开机启动

sudo systemctl enable nginx

systemctl 可能是 system controller 的意思,系统控制器,ctlcontroller 的缩写

其他两个命令

启动 nginx 服务

sudo systemctl start nginx

查看 nginx 服务的状态,启动或设置开机自启不成功时,可以这个命令查看错误信息

sudo systemctl status nginx

设置 uWSGI 开机启动

使用 service 设置 uWSGI 开机启动。

在这就要说一下,安装两遍 uWSGI 的事了。之前安装 uWSGI 是在虚拟环境下安装的,现在要设置开机启动,直接使用 uwsgi 命令,系统正常环境下是没有安装的,所以才安装两遍。

还是有问题,不使用虚拟环境,在虚拟环境下安装的包,在系统正常环境下是不能用的,因为没安装。漂亮!!!!!! 得,正常环境下再安装一遍呗。先把路跑通,再说其他的。

不进入 Django 虚拟环境,安装依赖。在项目根目录下执行以下命令

pip install -r requirements.txt

PSmysqlclient 包安装失败了。项目没用 msyql ,我也没纠结这个问题,直接没安装,注释掉了

创建 uWSGI 的启动文件。

新建个 sh 文件,在哪都行,我是在项目根目录下新建的,叫 start_uwsgi.sh,内容如下

#!/bin/sh
/home/breky/.local/bin/uwsgi --ini /home/breky/Workspace/djangodemo/Retrieve/Retrieve_uwsgi.ini

然后再执行 sh ./start_uwsgi.sh 命令,就可以启动 uWSGI

一共两行,解释一下:

#!/bin/sh:这个必需有,不然写 systemd 配置文件时会报错,Exec format error

/home/breky/.local/bin/uwsgiuWSGI 的绝对路径

--ini: 使用配置文件启动 uWSGI,后面跟 Retrieve_uwsgi.ini 的绝对路径。

PS:可以使用 whereis uwsgi 命令查看 uwsgi 的位置(绝对路径)

PS:因为 systemd 默认不继承 .bashrc 的内容,所以 systemd 的配置文件中所有文件、命令都需要写绝对路径

好了,可以用 start_uwsgi.sh 启动 uWSGI 了。

创建自启服务,需要用到这个文件,改下权限 sudo chmod 755 start_uwsgi.sh

创建 uWSGI 服务

进入 /usr/lib/systemd/system 目录,新建 uwsgi.service 文件。直接 vim 就行

# 此时,在 /usr/lib/systemd/system 中
sudo vim uwsgi.service

写入以下内容

[Unit]
Description=uwsgi-uwsgi-support
After=network.target
Before=nginx.service

[Service]
ExecStart=/home/breky/Workspace/djangodemo/Retrieve/start_uwsgi.sh
ExecReload=/bin/kill -HUP ( ps -ep | grep uwsgi)
User=breky
Type=forking

[Install]
WantedBy=multi-user.target

只需要注意两个地方:

一个是 [Service] 中的 ExecStart。后面跟的是 start_uwsgi.sh 的绝对路径。

另一个是 [Service] 中的 User。这个必需和安装 Django 依赖时的用户一致,不然会报错,Internal Server Error图 2

7.png|图 2: systemd 的配置文件中,不指定 User 会报 Internal Server Error 错误

启动服务试一下,sudo systemctl start uwsgi.service。网站可以访问了。

设置 uwsgi.service 服务开机自启

sudo sytemctl enable uwsgi.service

可以了,重启虚拟机。待完成重启,在主机上访问 192.168.106.132 ,网站可以访问了。

不出意外的出了意外,没有 CSS。这是因为 Nginx 没有找到静态文件。这个~,再说吧。

四、几个问题

部署过程,也是比较坎坷。虽然是完成了部署(忘记那个 CSS),但是没有达到预期的结果。想想中的,是使用虚拟环境部署的。算了,再研究吧。先把可能的问题记下来。

问题 1: 虚拟环境下,如何使用 systemd 实现 uWSGI 启动?

不用虚拟环境,还玩什么。一个服务器部署一个项目,家里有矿也不能这么干呀。

systemd 不继承 .bashrc 内容,start_uwsgi.sh 中就使用绝对路径就好嘛。

先把 virtualenvwrapper.sh 启动起来,再执行 workon Django,最后再执行 uwsgi 命令就行了呗。

理论上可行,找机会试试。

问题 2start_uwsgi.sh 的权限用不用改?

不用改吧。uwsgi.service 中指定了 User,与 start_uwsgi.sh 的用户是一致的,可能不需要改。

最后,哪天有时间,再把这两个问题试一下。

问题 3Nginx 开通 https

上面配置的 Nginx 是不能使用 https 打开网站的,需要用 http。就这样吧,不打算折腾 https 了。

待办:


参考文献

  1. Django+uWSGI+Nginx详细部署过程 By 瞿同学(Darren)
  2. Django、Nginx、uWSGI详解及配置示例 By 柃歌
  3. 总结uwsgi的安装、配置与设置开机自启 By 幸福清风
  4. systemd 介绍 By Tiffany的世界
  5. nginx + uwsgi + django open uwsgi_params failed (13: permission denied) By Answer of AKX

  1. 此 Django 教程由千峰教研院峰哥主讲 ↩︎

  2. 也有贴子说,把 socket 改成 http 就可以访问了,我没试 ↩︎